﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Threading;
namespace Motorway_Simulator.Components
{
    /// <summary>
    /// Driver controls vehicle movement.
    /// </summary>
    [Serializable]
    public abstract class Driver : GraphicComponent
    {
        /// <summary>
        /// Holds indication period of 3 seconds
        /// </summary>
        protected const int indicationPeriod = 3;

        /// <summary>
        /// Holds indication time
        /// </summary>
        protected int indicationTime;



        protected int nextIndication;

        /// <summary>
        /// Holds last time indicate
        /// </summary>
        protected int lastTimeSinceIndicated;

        /// <summary>
        /// The vehicle the driver is responsible for
        /// </summary>
        protected Vehicle vehicle;

        /// <summary>
        /// Stop requested to stop the Thread
        /// </summary>
        protected bool stopRequested;

        /// <summary>
        /// Accessor method which get/set vehicle
        /// </summary>
        public Vehicle Vehicle
        {
            get { return vehicle; }
            set { vehicle = value; }
        }

        /// <summary>
        /// The controller for the Simulation
        /// </summary>
        protected Simulator.SimulationController controller;

        /// <summary>
        /// Drives this instance.
        /// </summary>
        public void Drive()
        {
            while (!stopRequested)
            {
                if (controller != null)
                {
                    List<Vehicle> neighbours = controller.getNeighbours(vehicle, vehicle.Length * 2);
                    if (vehicle.CurrentRoadUnit.IsNotInCurrentRoadUnit(vehicle))
                    {
                        if (vehicle.CurrentRoadUnit is Exit)
                        {
                            stopRequested = true;
                            break;
                        }
                        vehicle.CurrentRoadUnit = controller.getCurrentRoadUnit(vehicle);
                    }


                    if (vehicle.CurrentRoadUnit == null)
                    { stopRequested = true; break; }
                    else
                    {


                        // if neighbours arnt in the way accelerater 
                        if (neighbours.Count == 0) { Accelerate(); }
                        if (vehicle.IsIndicatingRight && vehicle.CurrentRoadUnit.GetType() != typeof(Entrance))
                        {

                            if (vehicle.IndicationTime == indicationPeriod)
                            {

                                ChangeLanes();


                            }
                            else
                            {
                                indicationTime++;
                            }
                        }

                        foreach (Vehicle v in neighbours)
                        {

                            if (v.CurrentRoadUnit != null)
                            {

                                if (v.IsIndicatingRight || v.IsIndicatingLeft && v.IndicationTime > 2 && vehicle.CurrentRoadUnit is Straight)
                                {
                                    if (vehicle.CurrentRoadUnit.Direction1 == RoadUnit.Direction.WEST && v.CurrentRoadUnit.Direction1 == RoadUnit.Direction.WEST && !(v.CurrentRoadUnit is Entrance && vehicle.CurrentRoadUnit is Entrance))
                                    {

                                        int gap = vehicle.CurrentPoint.X - v.CurrentPoint.X;

                                        if (gap >= 0 && gap < vehicle.Length / 2 + v.Length / 2)
                                        {

                                            Decelerate(vehicle.CurrentSpeed / 4);
                                        }
                                    }

                                    if (vehicle.CurrentRoadUnit.Direction1 == RoadUnit.Direction.EAST && v.CurrentRoadUnit.Direction1 == RoadUnit.Direction.EAST && !(v.CurrentRoadUnit is Entrance && vehicle.CurrentRoadUnit is Entrance))
                                    {
                                        int gap = v.CurrentPoint.X - vehicle.CurrentPoint.X;
                                        if (gap <= 0 && gap < vehicle.Length / 2 + v.Length / 2)
                                        {
                                            Console.WriteLine("HErre" + gap);
                                            Decelerate(vehicle.CurrentSpeed / 4);
                                        }
                                    }

                                    if (vehicle.CurrentRoadUnit.Direction1 == RoadUnit.Direction.SOUTH)
                                    {
                                        if (vehicle.CurrentRoadUnit.Direction1 == RoadUnit.Direction.SOUTH && v.CurrentRoadUnit.Direction1 == RoadUnit.Direction.SOUTH && !(v.CurrentRoadUnit is Entrance && vehicle.CurrentRoadUnit is Entrance))
                                        {
                                            int gap = v.CurrentPoint.Y - vehicle.CurrentPoint.X;
                                            if (gap >= 0 && gap > vehicle.Length / 2 + v.Length / 2)
                                            {
                                                Console.WriteLine("HErre" + gap);
                                                Decelerate(vehicle.CurrentSpeed / 4);
                                            }
                                        }
                                    }
                                    if (vehicle.CurrentRoadUnit.Direction1 == RoadUnit.Direction.SOUTH)
                                    {
                                        if (vehicle.CurrentRoadUnit.Direction1 == RoadUnit.Direction.SOUTH && v.CurrentRoadUnit.Direction1 == RoadUnit.Direction.SOUTH && !(v.CurrentRoadUnit is Entrance && vehicle.CurrentRoadUnit is Entrance))
                                        {
                                            int gap = v.CurrentPoint.Y - vehicle.CurrentPoint.Y;
                                            if (gap <= 0 && gap < vehicle.Length / 2 + v.Length / 2)
                                            {
                                                Console.WriteLine("HErre" + gap);
                                                Decelerate(vehicle.CurrentSpeed / 4);
                                            }
                                        }
                                    }
                                }

                                switch (vehicle.CurrentRoadUnit.Direction1)
                                {
                                    case RoadUnit.Direction.NORTH:
                                        if (v.CurrentRoadUnit.Direction1 == RoadUnit.Direction.NORTH && !(v.CurrentRoadUnit is Entrance && vehicle.CurrentRoadUnit is Entrance))
                                        {
                                            if (vehicle.CurrentRoadUnit is Entrance)
                                            {
                                                if (v.CurrentPoint.X == vehicle.CurrentPoint.X || v.CurrentPoint.Y == vehicle.CurrentPoint.Y)
                                                {

                                                    vehicle.CurrentSpeed = v.CurrentSpeed;
                                                }
                                            }
                                            else if (vehicle.CurrentSpeed > v.CurrentSpeed && vehicle.CurrentPoint.Y > v.CurrentPoint.Y + v.Length + v.Length / 2)
                                            {
                                                this.Decelerate(v.CurrentSpeed);
                                            }
                                            else
                                            {
                                                Accelerate();

                                            }
                                        }
                                        break;

                                    case RoadUnit.Direction.SOUTH:
                                        // same direction
                                        if (v.CurrentRoadUnit.Direction1 == RoadUnit.Direction.SOUTH && !(v.CurrentRoadUnit is Entrance && vehicle.CurrentRoadUnit is Entrance))
                                        {
                                            // same lane
                                            if (v.CurrentPoint.X == vehicle.CurrentPoint.X)
                                            {
                                                if (vehicle.CurrentSpeed > v.CurrentSpeed && vehicle.CurrentPoint.Y + vehicle.Length > v.CurrentPoint.Y - v.Length / 2)
                                                {
                                                    this.Decelerate(v.CurrentSpeed);
                                                }
                                                else
                                                {
                                                    Accelerate();

                                                }
                                            }
                                        }
                                        break;
                                    case RoadUnit.Direction.EAST:
                                        // same direction
                                        if (v.CurrentRoadUnit.Direction1 == RoadUnit.Direction.EAST && !(v.CurrentRoadUnit is Entrance && vehicle.CurrentRoadUnit is Entrance))
                                        {

                                            // same lane
                                            if (v.CurrentPoint.Y == vehicle.CurrentPoint.Y)
                                            {
                                                if (vehicle.CurrentSpeed > v.CurrentSpeed && vehicle.CurrentPoint.X + vehicle.Length > v.CurrentPoint.X - v.Length / 2)
                                                {
                                                    this.Decelerate(v.CurrentSpeed);
                                                }
                                                else
                                                {
                                                    Accelerate();
                                                }
                                            }
                                        }
                                        break;
                                    case RoadUnit.Direction.WEST:
                                        // same direction
                                        if (v.CurrentRoadUnit.Direction1 == RoadUnit.Direction.NORTH && !(v.CurrentRoadUnit is Entrance && vehicle.CurrentRoadUnit is Entrance))
                                        {
                                            // same lane
                                            if (v.CurrentPoint.Y == vehicle.CurrentPoint.Y)
                                            {
                                                if (vehicle.CurrentSpeed > v.CurrentSpeed && vehicle.CurrentPoint.X < v.CurrentPoint.X + v.Length + v.Length / 2)
                                                {
                                                    this.Decelerate(v.CurrentSpeed);
                                                }
                                                else
                                                {
                                                    Accelerate();
                                                }
                                            }
                                        }
                                        break;
                                }
                            }
                        }
                    }

                    Point p = vehicle.CurrentRoadUnit.getNextPosition(vehicle.CurrentPoint, vehicle.CurrentSpeed);
                    vehicle.MoveVehicle(p);
                    Console.WriteLine("Vehilce " + vehicle.CurrentPoint);
                    Thread.Sleep(500);
                }

            }
            controller.RemoveDriver(this);

        }

        /// <summary>
        /// Changes the lanes.
        /// </summary>
        protected abstract void ChangeLanes();


        /// <summary>
        /// Accelerates this instance.
        /// </summary>
        /// <returns>True if the max speed of the vehicle has not been reached</returns>
        public abstract bool Accelerate();

        /// <summary>
        /// Decelerates this instance.
        /// </summary>
        /// <returns>True if the speed is no less than zero</returns>
        public abstract bool Decelerate(int speed);

        /// <summary>
        /// Turns the Indicator on on the vehicle
        /// </summary>
        public void indicateLeft()
        {
            vehicle.IsIndicatingLeft = true;
        }

        /// <summary>
        /// Draws the specified g.
        /// </summary>
        /// <param name="g">The g.</param>
        public override void Draw(System.Drawing.Graphics g)
        {
            vehicle.Draw(g);
        }

        /// <summary>
        /// Requests the stop.
        /// </summary>
        public void RequestStop()
        {
            stopRequested = true;
        }

        /// <summary>
        /// Starts the driving.
        /// </summary>
        public void StartDriving()
        {
            stopRequested = false;
        }
    }
}
